#!/usr/bin/perl -w
use strict; # always use strict, it's a good habit
use Parse::RecDescent; # see "perldoc Parse::RecDescent"
my $global_grammar = q{
  
  { my $last_type = undef; } # this action is executed when the 
  # grammar is created
  input: help | helpquit | quit | listlong | list | fileoption |
         show_last_type | set_type | order_dairy | order |
         <error>
  help: /help|h/i { ::usage(); 1; }
  helpquit: /-h/i { ::usage(); exit(0); }
  list: /list|l/i word(s?) { system('/bin/ls', @{$item{word}}); 1; }
  listlong: /-l|listlong|ll/i { system('/bin/ls -l'); 1; }
  fileoption: /-f/i word { print "Configuration file is $item{word}\n"; 1; }
  show_last_type: /show|s/i /last|l/i /type|t/ { ::show_last_type($last_type); 1; }
  
  set_type: /set|s/i /type|t/i word { $last_type = $item{word}; 1; }
  order_dairy: /order/i number(?) dairy_product
                { print "Dairy Order: @{$item{number}} $item{dairy_product}\n"; 1; }
  order: /order/i number(?) word
                { print "Order: @{$item{number}} $item{word}\n"; 1; }
  # come to Boston and try our frappes...
  dairy_product: /milk/i | /yogurt/i | /frappe|shake/i
  quit: /quit|q/i { exit(0) }
  word: /\S+/
  number: /\d+/
};
{ # this is a static scope!  do not remove!
 # $parse is only initialized once...
 my $parse = new Parse::RecDescent ($global_grammar);
 sub process_line
 {
  # get the input that was passed from above
  my $input = shift @_ || '';
  # return undef if the input is undef, or was not parsed correctly  
  $parse->input($input)
   or return undef; 
  # return 1 if everything went OK
  return 1;
 }
}
# first, process command-line arguments
if (@ARGV)			       
{
 process_line(join ' ', @ARGV);
}
                        do  {
 print "Type 'help' for help, or 'quit' to quit\n-> ";
 my $input = <STDIN>; # a variable to hold user input 
 print "You entered $input\n"; # let the user know what we got
 
 process_line($input);
} while (1); # only 'quit' or ^C can exit the loop
exit; # implicit exit here anyway
# print out the help and exit
sub usage
{
 print <<EOHIPPUS;
first.pl [-l] [-h] [-f FILENAME]
The -l switch lists the files in the current directory, using /bin/ls -l.
The -f switch selects a different configuration file.  The -h
switch prints this help.  Without the -l or -h arguments, will show
a command prompt.
Commands you can use at the prompt:
 order [number] product: order a product, either dairy (milk, yogurt, 
 frappe, shake), or anything else.
 set|s type|t word     : set the current type word
 show|s last|l type|t  : show the current type word
 list | l              : list the files in the current directory
 listlong | ll | -l    : list the files in the current directory in long format
 help | h              : print out this help
 quit | q              : quit the program
 
EOHIPPUS
}
sub show_last_type
{
 my $type = shift;
 return unless defined $type; # do nothing for an undef type word
 print "The last type selected was $type\n";
}